#ifndef _node
#define _node

#include <new>
#include <iostream>
#include <deque>
#include <cfloat>
#include <algorithm>

class RoutingMessage;
class Table;
class Link;
class SimulationContext;

#include "table.h"

const double INFINITY = DBL_MAX - 10000; // surely link costs won't exceed 10000

using namespace std;

class Node {
private:
	unsigned int number;
	SimulationContext *context;
	double bw;
	double lat;
	Table m_RoutingTable;
	map<unsigned int, Node*> m_ForwardingTable;

	/////////////////////////////////////////////////////////////
	// 
	// Link State
	// 
	/////////////////////////////////////////////////////////////

#if defined(LINKSTATE)

#endif

	/////////////////////////////////////////////////////////////
	// 
	// Distance Vector
	// 
	/////////////////////////////////////////////////////////////

#if defined(DISTANCEVECTOR)

#endif

	// students will add protocol-specific data here

public:
	Node(const unsigned n, SimulationContext *c, double b, double l);
	Node();
	Node(const Node &rhs);
	Node & operator=(const Node &rhs);
	virtual ~Node();

	virtual bool Matches(const Node &rhs) const;

	virtual void SetNumber(const unsigned n);
	virtual unsigned GetNumber() const;

	virtual void SetLatency(const double l);
	virtual double GetLatency() const;
	virtual void SetBW(const double b);
	virtual double GetBW() const;

	virtual void SendToNeighbors(RoutingMessage *m);
	virtual void SendToNeighbor(const Node *n, const RoutingMessage *m);
	virtual deque<Node*> *GetNeighbors();
	virtual void SetTimeOut(const double timefromnow);

	void ConstructRoutingTable(Node *curNode, deque<Node*> *nodeList);

#if defined(LINKSTATE)
	void UpdateAllRoutingTable(deque<Node*> nodeList);
	void PrintNodeList(deque<Node *> nodeList);
	void PrintLinkList(deque<Link *> nodeList);
	void PrintShortestPath(unsigned dest);
	void PrintRoutingTable();
	void PrintForwardingTable();
    bool IncludeNode(unsigned num, deque<Node*> nodeList);
#endif

#if defined(DISTANCEVECTOR)
	void PrintRoutingTable();
	void PrintForwardingTable();
	RoutingMessage *GetVectorInRoutingMessage();
	void UpdateNodeRoutingTable(const RoutingMessage *m);
	void UpdateForwardingTable(unsigned int nodeID, Node *nextHopNode);
	//bool RecalculateLocalDistanceVector(const RoutingMessage *m);
	bool RecalculateLocalDistanceVector();
	double GetLinkCost(unsigned int uintSource, unsigned int uintDest);
	void InitializeForwardingTable(deque<Node*> *nodeList);
#endif

	//
	// Students will WRITE THESE
	//
	virtual void LinkHasBeenUpdated(const Link *l);
	virtual void ProcessIncomingRoutingMessage(const RoutingMessage *m);
	virtual void TimeOut();
	virtual Node *GetNextHop(const Node *destination);
	virtual Table *GetRoutingTable();

	virtual ostream & Print(ostream &os) const;

};

inline ostream & operator<<(ostream &os, const Node &n) {
	return n.Print(os);
}

#endif
